# Python 装饰器示例

print("=" * 50)
print("Python 装饰器")

print("""
1. 什么是装饰器：装饰器的基本概念和语法
2. 装饰器的原理：理解装饰器是如何工作的
3. 带参数的函数装饰器：处理被装饰函数的参数
4. 带参数的装饰器：创建可配置的装饰器
5. 类装饰器：使用类作为装饰器
6. 多个装饰器：同时应用多个装饰器
7. 保留原函数元信息的装饰器：使用functools.wraps
8. 实用装饰器示例：计时、缓存、权限检查等
9. 装饰器工厂：创建可复用的装饰器生成器
10. 装饰器在类中的应用：属性、静态方法、类方法装饰器
11. 高级装饰器示例：单例模式实现
12. 装饰器的实际应用：日志记录功能
""")

print("=" * 50)

# 1. 什么是装饰器
print("\n1. 什么是装饰器")
print("-" * 30)

# 装饰器本质上是一个函数，它可以在不修改原函数代码的情况下，给函数增加新的功能

def my_decorator(func):
    def wrapper():
        print("函数执行前做一些操作")
        func()
        print("函数执行后做一些操作")
    return wrapper

@my_decorator
def say_hello():
    print("Hello, World!")

print("调用被装饰的函数:")
say_hello()

# 2. 装饰器的原理
print("\n\n2. 装饰器的原理")
print("-" * 30)

# 上面的 @my_decorator 语法糖等价于:
def say_goodbye():
    print("Goodbye!")

# 手动装饰
say_goodbye = my_decorator(say_goodbye)
print("手动装饰后调用函数:")
say_goodbye()

# 3. 带参数的函数装饰器
print("\n\n3. 带参数的函数装饰器")
print("-" * 30)

def arg_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"函数 {func.__name__} 被调用，参数: args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 执行完毕")
        return result
    return wrapper

@arg_decorator
def add(a, b):
    print(f"计算 {a} + {b}")
    return a + b

@arg_decorator
def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

print("调用带参数的被装饰函数:")
result = add(3, 5)
print(f"add(3, 5) = {result}")

greet("张三")
greet("李四", greeting="你好")

# 4. 带参数的装饰器
print("\n\n4. 带参数的装饰器")
print("-" * 30)

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(times):
                print(f"第 {i+1} 次调用:")
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print("Hi!")

print("调用被带参数的装饰器装饰的函数:")
say_hi()

# 5. 类装饰器
print("\n\n5. 类装饰器")
print("-" * 30)

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"函数 {self.func.__name__} 被调用了 {self.count} 次")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello_again():
    print("Hello again!")

print("调用被类装饰器装饰的函数:")
say_hello_again()
say_hello_again()
say_hello_again()

# 6. 多个装饰器
print("\n\n6. 多个装饰器")
print("-" * 30)

def bold(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return f"<b>{result}</b>"
    return wrapper

def italic(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return f"<i>{result}</i>"
    return wrapper

@bold
@italic
def get_text():
    return "Hello, World!"

print("调用被多个装饰器装饰的函数:")
print(get_text())

# 注意装饰器的应用顺序是从下到上（最靠近函数的先应用）
# 上面的 @bold @italic 等价于 bold(italic(get_text))

# 7. 保留原函数元信息的装饰器
print("\n\n7. 保留原函数元信息的装饰器")
print("-" * 30)

# 不使用 functools.wraps 的装饰器
def no_wrap_decorator(func):
    def wrapper(*args, **kwargs):
        """这是wrapper函数的文档字符串"""
        return func(*args, **kwargs)
    return wrapper

# 使用 functools.wraps 的装饰器
from functools import wraps

def wrap_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """这是wrapper函数的文档字符串"""
        return func(*args, **kwargs)
    return wrapper

@no_wrap_decorator
def func1():
    """这是func1的文档字符串"""
    pass

@wrap_decorator
def func2():
    """这是func2的文档字符串"""
    pass

print("不使用 wraps 保留元信息:")
print(f"函数名: {func1.__name__}")
print(f"文档字符串: {func1.__doc__}")

print("\n使用 wraps 保留元信息:")
print(f"函数名: {func2.__name__}")
print(f"文档字符串: {func2.__doc__}")

# 8. 实用装饰器示例
print("\n\n8. 实用装饰器示例")
print("-" * 30)

# 计时装饰器
import time

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"函数 {func.__name__} 执行时间: {end_time - start_time:.4f} 秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "任务完成"

print("计时装饰器示例:")
result = slow_function()
print(result)

# 缓存装饰器
def cache(func):
    cached_results = {}

    @wraps(func)
    def wrapper(*args, **kwargs):
        # 创建参数的键
        key = str(args) + str(sorted(kwargs.items()))

        if key in cached_results:
            print(f"缓存命中: {func.__name__}{args}")
            return cached_results[key]

        print(f"计算并缓存: {func.__name__}{args}")
        result = func(*args, **kwargs)
        cached_results[key] = result
        return result

    return wrapper

@cache
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print("\n缓存装饰器示例:")
print(f"fibonacci(5) = {fibonacci(5)}")
print("再次计算 fibonacci(5):")
print(f"fibonacci(5) = {fibonacci(5)}")

# 权限检查装饰器
def require_permission(permission):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 模拟当前用户权限
            user_permissions = ['read', 'write']

            if permission in user_permissions:
                return func(*args, **kwargs)
            else:
                return f"权限不足: 需要 '{permission}' 权限"
        return wrapper
    return decorator

@require_permission('read')
def read_data():
    return "读取数据成功"

@require_permission('delete')
def delete_data():
    return "删除数据成功"

print("\n权限检查装饰器示例:")
print(read_data())
print(delete_data())

# 9. 装饰器工厂
print("\n\n9. 装饰器工厂")
print("-" * 30)

def create_validator(*validators):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 验证参数
            for i, (arg, validator) in enumerate(zip(args, validators)):
                if not validator(arg):
                    raise ValueError(f"参数 {i+1} 验证失败: {arg}")

            return func(*args, **kwargs)
        return wrapper
    return decorator

# 定义验证函数
def is_positive(x):
    return x > 0

def is_string(x):
    return isinstance(x, str)

@create_validator(is_positive, is_string)
def process_data(number, text):
    return f"处理数据: 数字={number}, 文本={text}"

print("装饰器工厂示例:")
try:
    print(process_data(5, "hello"))
    print(process_data(-1, "world"))  # 这会引发异常
except ValueError as e:
    print(f"验证错误: {e}")

# 10. 装饰器在类中的应用
print("\n\n10. 装饰器在类中的应用")
print("-" * 30)

class MyClass:
    def __init__(self):
        self._value = 0

    @property
    def value(self):
        """获取_value属性"""
        return self._value

    @value.setter
    def value(self, new_value):
        """设置_value属性"""
        if new_value < 0:
            raise ValueError("值不能为负数")
        self._value = new_value

    @staticmethod
    def static_method():
        """静态方法"""
        return "这是一个静态方法"

    @classmethod
    def class_method(cls):
        """类方法"""
        return f"这是 {cls.__name__} 类的方法"

# 使用类中的装饰器
obj = MyClass()
print("属性装饰器示例:")
print(f"初始值: {obj.value}")
obj.value = 10
print(f"设置后的值: {obj.value}")

print("\n静态方法和类方法:")
print(MyClass.static_method())
print(MyClass.class_method())

# 11. 高级装饰器示例 - 单例模式
print("\n\n11. 高级装饰器示例 - 单例模式")
print("-" * 30)

def singleton(cls):
    instances = {}

    @wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance

@singleton
class DatabaseConnection:
    def __init__(self):
        self.connection_id = id(self)
        print(f"创建数据库连接: {self.connection_id}")

    def query(self, sql):
        return f"执行查询: {sql}"

print("单例模式装饰器示例:")
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(f"db1 ID: {db1.connection_id}")
print(f"db2 ID: {db2.connection_id}")
print(f"db1 和 db2 是同一个实例: {db1 is db2}")

# 12. 装饰器的实际应用 - 日志记录
print("\n\n12. 装饰器的实际应用 - 日志记录")
print("-" * 30)

def log_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        args_str = ', '.join([repr(arg) for arg in args])
        kwargs_str = ', '.join([f"{k}={repr(v)}" for k, v in kwargs.items()])
        all_args = ', '.join(filter(None, [args_str, kwargs_str]))

        print(f"[LOG] 调用 {func.__name__}({all_args})")
        result = func(*args, **kwargs)
        print(f"[LOG] {func.__name__} 返回: {repr(result)}")
        return result
    return wrapper

@log_calls
def calculate_area(length, width, unit="平方米"):
    return length * width

print("日志记录装饰器示例:")
area = calculate_area(5, 3, unit="平方米")
print(f"计算结果: {area}")

print("\n" + "=" * 50)
print("装饰器示例结束")
print("=" * 50)
